﻿using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Routine.Api.Services;
using Routine.Api.Models;
using Routine.Api.Entities;
using Microsoft.AspNetCore.JsonPatch;

namespace Routine.Api.Controllers
{
    [ApiController]
    [Route("api/companies/{companyId}/employees")]//看懂这个路由；
    //具有父子关系的路由。
    public class EmployeesController : ControllerBase
    {
        private readonly IMapper _mapper;
        private readonly ICompanyRepository _companyRepository;

        public EmployeesController(IMapper mapper, ICompanyRepository companyRepository)
        {
            _mapper = mapper
                 ?? throw new ArgumentNullException(nameof(mapper)); //抛出为空的异常
            _companyRepository = companyRepository
                ?? throw new ArgumentNullException(nameof(companyRepository));
        }
        [HttpGet]
        public async Task<ActionResult<IEnumerable<EmployeeDto>>>   //此处的Acton不能用IActionResult,已经有具体的实现类了；
            GetEmployeesAsync(Guid companyId,[FromQuery(Name ="gender")]string genderDisplay,string q)
            /*genderDisplay不可能来自于路由,所以要来自查询字符串参数，（可以用Name对查询字符串进行指定），
             * 如果名字不一致就会忽略；
             * 通常过滤和查询都是在一起的
             * q相当于一个搜索条件。
             * 如果查询条件较多的话，可以建立一个类。把参数都放到这个类里面就可以了
             */
        {
            if (!await _companyRepository.CompanyExistsAsync(companyId))
            {
                return NotFound();//如果没有找到的话，就返回404;
            }
            var employees = await _companyRepository.GetEmployeesAsync(companyId,genderDisplay,q);//获取员工的信息；q是搜索条件。
            var emplyeeDtos = _mapper.Map<IEnumerable<EmployeeDto>>(employees); //将Employees映射为EmplyeesDto；
            return Ok(emplyeeDtos);



            //Ctrl + M + O: 折叠所有方法
            //Ctrl + M + M: 折叠或者展开当前方法
            //Ctrl + M + L: 展开所有方法
        }
        [HttpGet("{employeeId}",Name =nameof(GetEmployeeAsync))]  //路由名字后边要加{}
        public async Task<ActionResult<EmployeeDto>>   //此处的Acton不能用IActionResult
          GetEmployeeAsync(Guid companyId, Guid employeeId)
        {
            if (!await _companyRepository.CompanyExistsAsync(companyId))
            {
                return NotFound();//如果没有找到的话，就返回404;
            }
            var employee = await _companyRepository.GetEmployeeAsync(companyId,employeeId);//善于使用单复数
            if (employee==null)
            {
                return NotFound();
            }
            var emplyeeDto = _mapper.Map<EmployeeDto>(employee); //注意单复数的变化；是类不是数组；
            return Ok(emplyeeDto);
        }
        [HttpPost]
        public async Task<ActionResult<EmployeeDto>> CreateEmployeeForCompany(Guid companyId, EmployeeAddDto employee)
        {
            if (!await _companyRepository.CompanyExistsAsync(companyId))  //检查是否有一个公司的Id为companyId
            {
                return NotFound();
            }

            var entity = _mapper.Map<Employee>(employee);  //使用映射；
            _companyRepository.AddEmployee(companyId, entity);
            await _companyRepository.SaveAsync();

            var dotToReturn = _mapper.Map<EmployeeDto>(entity);//把entity再映射为dto
            return CreatedAtRoute(nameof(GetEmployeeAsync),
                new { companyId = companyId, employeeId = dotToReturn.Id }, dotToReturn);//返回类型的确定
                   //companyId 和 dotToReturn两个参数写在 new{} 类里面。
        }

        [HttpPut("{employeeId}")]
        public async Task<ActionResult<EmployeeDto>> UpdateEmployeeForCompany(//如果不想更新的部分，要把原来的值写上，不然要生成默认值。
            Guid companyId, Guid employeeId,
            EmployeeUpdateDto employee)
        {
            if (!await _companyRepository.CompanyExistsAsync(companyId))
            {
                return NotFound();
            }
            var employeeEntity = await _companyRepository.GetEmployeeAsync(companyId, employeeId);
            if (employeeEntity==null)  //如果该默认值得话，可以
            {
                var employeeToAddEntity = _mapper.Map<Employee>(employee);
                employeeToAddEntity.Id = employeeId;
                _companyRepository.AddEmployee(companyId, employeeToAddEntity);
                await _companyRepository.SaveAsync();
                var dtoToReturn = _mapper.Map<EmployeeDto>(employeeToAddEntity);
                return CreatedAtRoute(nameof(GetEmployeeAsync), //应该是有错误。
                    new { companyId, employeeId = dtoToReturn.Id }, dtoToReturn);
            }



            //entity转化为updateDto
            //把传进来的employee的值更新到updateDto
            //把updateDto映射回entity
            //因为有了AutoMapper，现在一行代码就可以实现了；
            _mapper.Map(employee, employeeEntity);
            _companyRepository.UpdateEmployee(employeeEntity);
            await _companyRepository.SaveAsync();
            return NoContent();//返回一个204；
        }

        [HttpPatch("{employeeId}")]
        public async Task<IActionResult> PartiallyUpdateEmployeeForCompany(//产看前端的postMan怎么请求的。
                                                                                  //这里面很多的东西都没增加。
            Guid companyId,
            Guid employeeId,
            JsonPatchDocument<EmployeeUpdateDto> patchDocument)//这个传入的是个patch
        {
            if (!await _companyRepository.CompanyExistsAsync(companyId))
            {
                return NotFound();
            }
            var employeeEntity = await _companyRepository.GetEmployeeAsync(companyId, employeeId);

            if (employeeEntity == null)//如果要查询的这个代码不存在，那么就转化为创建，要在这里里面改；
            {
                return NotFound();
            }
            var dtoToPatch = _mapper.Map<EmployeeUpdateDto>(employeeEntity);

            //需要验证，如果add里面的添加一个不存在的属性，或者是更改只读属性
            patchDocument.ApplyTo(dtoToPatch,ModelState);
            

            _mapper.Map(dtoToPatch, employeeEntity);
            _companyRepository.UpdateEmployee(employeeEntity);
            await _companyRepository.SaveAsync();
            return NoContent();
        }
        [HttpDelete("{employeeId}")]
        public async Task<IActionResult> DeleteEmployeeForCompany(Guid companyId, Guid employeeId)
        {
            if (!await _companyRepository.CompanyExistsAsync(companyId))
            {
                return NotFound();
            }
            var employeeEntity = await _companyRepository.GetEmployeeAsync(companyId, employeeId);
            if (employeeEntity==null)
            {
                return NotFound();
            }
            _companyRepository.DeleteEmployee(employeeEntity);
            await _companyRepository.SaveAsync();
            return NoContent();
        }


    }
}
